#include "SemanticNodeField.h"
#include "../errors_warnings.h"
/**
 *  @fn	SemanticNodeField::SemanticNodeField(const SyntaxTreeNode *modifiers,
 *  	const SyntaxTreeNode *varType, const SyntaxTreeNode *varName,
 *  	const SemanticNode *parentNode) : SemanticNode(*varName, parent)
 *
 *  @brief	Constructor.
 *
 *  @author	Nikola Novak
 *  @date	6/6/2009
 *
 *  @param	modifiers	If non-null, the modifiers.
 *  @param	varType	If non-null, type of the variable.
 *  @param	varName	If non-null, name of the variable.
 *  @param	parentNode	If non-null, the parent node.
 */
SemanticNodeField::SemanticNodeField(const SyntaxTreeNode *modifiers, const SyntaxTreeNode *varType, const SyntaxTreeNode *varName, SemanticNode *parentNode) :	SemanticNode(parentNode), ValueType(getNextUniqueID()) {
	// obradjivanje modifikatora
	this->mod = 0x00;
	bool privPublicProt = false;
	if (modifiers != NULL) {
		for (int i = 0; i < modifiers->Nodes->GetCount(); ++i) {
			switch(modifiers->Nodes->GetData(i)->Production){
			case Gr_FieldMod__const:
				if (!isConstant())
					makeConstant();
				else {
					LexicUnit lu = CompilerData->Units->GetLexicUnit(modifiers->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
					CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_MODIFIER_CONST);
				}
				break;
			case Gr_FieldMod__static:
				if (isStatic()){
					LexicUnit lu = CompilerData->Units->GetLexicUnit(modifiers->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
					CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_MODIFIER_STATIC);
				}
				mod |= Static;
				break;
			case Gr_FieldMod__private:
				if (privPublicProt){
					LexicUnit lu = CompilerData->Units->GetLexicUnit(modifiers->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
					CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
					break;
				}
				privPublicProt = true;
				mod |= Private;
				break;
			case Gr_FieldMod__protected:
				if (privPublicProt){
					LexicUnit lu = CompilerData->Units->GetLexicUnit(modifiers->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
					CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
					break;
				}
				privPublicProt = true;
				mod |= Protected;
				break;
			case Gr_FieldMod__public:
				if (privPublicProt){
					LexicUnit lu = CompilerData->Units->GetLexicUnit(modifiers->Nodes->GetData(i)->Nodes->GetData(0)->LexUnitID);
					CompilerData->ErrorWarningReport->ReportError(&lu, ERR_SEM_MULTIPLE_ACCESS_MODIFIERS);
					break;
				}
				privPublicProt = true;
				mod |= Public;
				break;
			default:;
				// ako je sintaksa dobro napravljena ovo se ne bi smjelo dogodit
			}
		}
	}
	if (!privPublicProt) mod |= Private;

	// obrada imena varijable i dimenzionalnosti
	initExpression = NULL;
	name = CompilerData->Units->GetLexicUnitString(&CompilerData->Units->GetLexicUnit(varName->Nodes->GetData(0)->Nodes->GetData(0)->LexUnitID));


	// obrada tipa podatka
	setType(varType, varName->Nodes->GetData(0)->Nodes->GetData(1)->Nodes->GetCount());
}
/**
 *  @fn	void SemanticNodeField::addExpression(SemanticNodeExpression *nodeExpression)
 *
 *  @brief	Adds an expression used to initialize this field.
 *
 *  @author	Nikola Novak.
 *  @date	6/6/2009.
 *
 *  @param	nodeExpression	A semantic node representing the expression.
 */
void SemanticNodeField::setInitExpression(SemanticNodeExpression *nodeExpression) {
	initExpression = nodeExpression;
}
/**
 *  @fn	std::string Variable::getName(void)
 *
 *  @brief	Gets the name.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	The name.
 */
std::string SemanticNodeField::getName(void) {
	return name;
}
/**
 *  @fn	bool isInitialized()
 *
 *  @brief	Query if this object is initialized.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	true if initialized, false if not.
 */
bool SemanticNodeField::isInitialized() {
	return initExpression != NULL;
}

/**
 *  @fn	bool Variable::isPublic(void)
 *
 *  @brief	Query if this object is public.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	true if public, false if not.
 */
bool SemanticNodeField::isPublic(void) {
	return mod & Public;
}

/**
 *  @fn	bool Variable::isPrivate(void)
 *
 *  @brief	Query if this object is private.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	true if private, false if not.
 */
bool SemanticNodeField::isPrivate(void) {
	return mod & Private;
}

/**
 *  @fn	bool Variable::isProtected(void)
 *
 *  @brief	Query if this object is protected.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	true if protected, false if not.
 */
bool SemanticNodeField::isProtected(void) {
	return mod & Protected;
}

/**
 *  @fn	bool Variable::isStatic(void)
 *
 *  @brief	Query if this object is static.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @return	true if static, false if not.
 */
bool SemanticNodeField::isStatic(void) {
	return mod & Static;
}
/**
 *  @fn	std::string toDebugString(int tab)
 *
 *  @brief	Pretvara varijablu u izravnati string.
 *
 *  @author	Nikola Novak
 *  @date	6/1/2009
 *
 *  @param	tab	Broj razmaka ispred stringa.
 *
 *  @return	This object as a std::string.
 */
std::string SemanticNodeField::toDebugString(int tab) {
	std::ostringstream res;
	for (int i = 0; i < tab; i++) res << DEBUG_STRING_RAZMAK;
	if (mod & Private) res << "private ";
	if (mod & Protected) res << "protected ";
	if (mod & Public) res << "public ";
	if (mod & Static) res << "static ";
	if (isConstant()) res << "const ";
	res << this->getTypeDebugString() << " " << name;
	for (int x = 0; x < dimensions.size(); ++x) res << "[]";
	res << std::endl;
	if (isInitialized())	res << initExpression->toDebugString(tab + 1);
	else {
		for (int i = 0; i < tab + 1; i++) res << DEBUG_STRING_RAZMAK;
		res << "null" << std::endl;
	}
	return res.str();
}





std::vector<SemanticNodeField *> SemanticNodeField::analyzeNodeField(const SyntaxTreeNode *fieldNode, SemanticNode *parent) {
	std::vector<SemanticNodeField *> snf;
	SyntaxTreeNode *modifiers = fieldNode->Nodes->GetData(0);
	SyntaxTreeNode *varType = fieldNode->Nodes->GetData(2);
	SyntaxTreeNode *varName = fieldNode->Nodes->GetData(3);
	while (true) {
		SemanticNodeField *newField = new SemanticNodeField(modifiers, varType, varName, parent);
		SyntaxTreeNode *equals = varName->Nodes->GetData(1);
		if (equals->Production == Gr_Equals__opAssign_Expression) {
			newField->setInitExpression(OurSemanticAnalyzer::analyzeNodeExpression(equals->Nodes->GetData(1), newField)); //new SemanticNodeExpression(equals->Nodes->GetData(1), parent));
		}
		snf.push_back(newField);
		varName = varName->Nodes->GetData(2);
		if (varName->Production == Gr_FieldNamesAdd__epsilon) break;
 	varName = varName->Nodes->GetData(1);
	}
	return snf;
}
